import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

/**
 * 数据存储类
 */
class Storage {
  constructor() {
    this.dataDir = path.join(__dirname, '../data')
    this.userFile = path.join(this.dataDir, 'users.json')
    this.signLogFile = path.join(this.dataDir, 'sign_logs.json')
    
    this.init()
  }

  /**
   * 初始化数据目录和文件
   */
  init() {
    // 创建数据目录
    if (!fs.existsSync(this.dataDir)) {
      fs.mkdirSync(this.dataDir, { recursive: true })
      logger.info('[签到插件] 创建数据目录')
    }

    // 初始化用户文件
    if (!fs.existsSync(this.userFile)) {
      this.saveUsers({})
    }

    // 初始化签到日志文件
    if (!fs.existsSync(this.signLogFile)) {
      this.saveSignLogs({})
    }
  }

  /**
   * 读取JSON文件
   */
  readJSON(filePath) {
    try {
      const data = fs.readFileSync(filePath, 'utf8')
      return JSON.parse(data)
    } catch (error) {
      logger.error(`[签到插件] 读取文件失败: ${filePath}`, error)
      return {}
    }
  }

  /**
   * 写入JSON文件
   */
  writeJSON(filePath, data) {
    try {
      fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8')
      return true
    } catch (error) {
      logger.error(`[签到插件] 写入文件失败: ${filePath}`, error)
      return false
    }
  }

  /**
   * 获取所有用户数据
   */
  getUsers() {
    return this.readJSON(this.userFile)
  }

  /**
   * 保存用户数据
   */
  saveUsers(users) {
    return this.writeJSON(this.userFile, users)
  }

  /**
   * 获取用户信息
   */
  getUser(qq) {
    const users = this.getUsers()
    return users[qq] || null
  }

  /**
   * 保存/更新用户信息
   */
  saveUser(qq, userData) {
    const users = this.getUsers()
    users[qq] = {
      ...users[qq],
      ...userData,
      updateTime: Date.now()
    }
    return this.saveUsers(users)
  }

  /**
   * 删除用户
   */
  deleteUser(qq) {
    const users = this.getUsers()
    delete users[qq]
    return this.saveUsers(users)
  }

  /**
   * 获取用户的Cookie
   */
  getUserCookie(qq) {
    const user = this.getUser(qq)
    return user?.cookie || null
  }

  /**
   * 保存用户Cookie
   * @param {string} qq - 用户QQ号
   * @param {string} cookie - Cookie字符串
   * @param {object|string} uid - UID（对象格式：{ gs: 'xxx', sr: 'xxx' }，或字符串会合并到现有UID）
   */
  saveUserCookie(qq, cookie, uid) {
    // 获取现有用户数据
    const user = this.getUser(qq) || {}
    let existingUid = user.uid || {}
    
    // 如果现有UID是字符串（旧版格式），转换为对象
    if (typeof existingUid === 'string') {
      logger.info(`[签到插件] 迁移用户 ${qq} 的UID数据: "${existingUid}" -> {"gs":"${existingUid}"}`)
      existingUid = { gs: existingUid }
    }
    
    // 清理现有UID，确保只包含有效键
    existingUid = this.cleanUidObject(existingUid)
    
    // 合并新UID：无论传入的是字符串还是对象，都要保留现有其他游戏的UID
    let newUid
    if (typeof uid === 'string') {
      // 字符串UID默认为原神
      newUid = { ...existingUid, gs: uid }
    } else if (uid && typeof uid === 'object') {
      // 对象UID：合并到现有UID
      newUid = { ...existingUid, ...uid }
    } else {
      // 无效UID，保持现有UID不变
      newUid = existingUid
    }
    
    // 清理合并后的UID对象，只保留有效键
    newUid = this.cleanUidObject(newUid)
    
    return this.saveUser(qq, { cookie, uid: newUid })
  }

  /**
   * 保存用户游戏UID
   * @param {string} qq - 用户QQ号
   * @param {string} game - 游戏标识 ('gs', 'sr')
   * @param {string} uid - 游戏UID
   */
  saveUserUid(qq, game, uid) {
    const user = this.getUser(qq) || {}
    let uidObj = user.uid || {}
    
    // 检测旧版数据格式
    if (typeof uidObj === 'string') {
      logger.warn(`[签到插件] 检测到旧版UID格式，QQ:${qq}，自动迁移...`)
      uidObj = { gs: uidObj }
    }
    
    // 清理现有UID对象
    uidObj = this.cleanUidObject(uidObj)
    
    // 更新指定游戏的UID
    uidObj[game] = uid
    
    return this.saveUser(qq, { uid: uidObj })
  }

  /**
   * 获取用户游戏UID
   * @param {string} qq - 用户QQ号
   * @param {string} game - 游戏标识 ('gs', 'sr')
   * @returns {string|null}
   */
  getUserUid(qq, game) {
    const user = this.getUser(qq)
    if (!user || !user.uid) return null
    
    // 检测旧版数据格式
    if (typeof user.uid === 'string') {
      logger.warn(`[签到插件] 检测到旧版UID格式，QQ:${qq}，请重新同步Cookie`)
      return null
    }
    
    return user.uid[game] || null
  }
  
  /**
   * 检查用户数据是否为旧版格式
   * @param {string} qq - 用户QQ号
   * @returns {boolean}
   */
  isOldDataFormat(qq) {
    const user = this.getUser(qq)
    if (!user) return false
    
    // 检查uid是否为字符串（旧版格式）
    return typeof user.uid === 'string'
  }

  /**
   * 清理UID对象，只保留有效的游戏标识键（gs, sr）
   * @param {object} uidObj - UID对象
   * @returns {object} 清理后的UID对象
   */
  cleanUidObject(uidObj) {
    if (!uidObj || typeof uidObj !== 'object') {
      return {}
    }
    
    const cleaned = {}
    const validKeys = ['gs', 'sr'] // 只保留有效的游戏标识键
    
    for (const key of validKeys) {
      if (uidObj[key] && typeof uidObj[key] === 'string' && uidObj[key].trim()) {
        cleaned[key] = uidObj[key].trim()
      }
    }
    
    return cleaned
  }

  /**
   * 验证并修复用户UID数据
   * @param {string} qq - 用户QQ号
   * @param {object} usersObj - 可选的用户对象（用于批量处理）
   * @returns {boolean} 是否进行了修复
   */
  validateAndFixUserUid(qq, usersObj = null) {
    const user = usersObj ? usersObj[qq] : this.getUser(qq)
    if (!user || !user.uid) return false
    
    // 如果是字符串（旧版格式），不在这里处理
    if (typeof user.uid === 'string') {
      return false
    }
    
    // 检查是否有无效键
    const keys = Object.keys(user.uid)
    const hasInvalidKeys = keys.some(key => !['gs', 'sr'].includes(key))
    
    if (hasInvalidKeys) {
      logger.warn(`[签到插件] 检测到用户 ${qq} 的UID数据存在无效键: ${keys.join(', ')}`)
      const cleanedUid = this.cleanUidObject(user.uid)
      
      // 如果提供了用户对象，直接修改；否则重新获取并保存
      if (usersObj) {
        usersObj[qq].uid = cleanedUid
        usersObj[qq].updateTime = Date.now()
      } else {
        const users = this.getUsers()
        users[qq].uid = cleanedUid
        users[qq].updateTime = Date.now()
        this.saveUsers(users)
      }
      
      logger.info(`[签到插件] 已清理用户 ${qq} 的UID数据: ${JSON.stringify(cleanedUid)}`)
      return true
    }
    
    return false
  }

  /**
   * 批量清理所有用户的UID数据
   * @returns {object} { total, cleaned, migrated }
   */
  cleanAllUsersUid() {
    const users = this.getUsers()
    let total = 0
    let cleaned = 0
    let migrated = 0
    let modified = false
    
    for (const qq of Object.keys(users)) {
      total++
      
      // 跳过没有 uid 字段的用户
      if (!users[qq] || !users[qq].uid) {
        continue
      }
      
      // 处理旧版字符串格式（迁移为对象格式）
      if (typeof users[qq].uid === 'string') {
        const oldUid = users[qq].uid
        users[qq].uid = { gs: oldUid }
        users[qq].updateTime = Date.now()
        logger.info(`[签到插件] 迁移用户 ${qq} 的UID数据: "${oldUid}" -> {"gs":"${oldUid}"}`)
        migrated++
        modified = true
        continue
      }
      
      // 清理无效键（传递 users 对象以避免重复读写）
      if (this.validateAndFixUserUid(qq, users)) {
        cleaned++
        modified = true
      }
    }
    
    // 保存更新后的用户数据（只保存一次）
    if (modified) {
      this.saveUsers(users)
    }
    
    logger.info(`[签到插件] UID数据清理完成: 总用户${total}个, 清理无效键${cleaned}个, 迁移旧格式${migrated}个`)
    return { total, cleaned, migrated }
  }

  /**
   * 获取用户的自动签到配置
   * @param {string} qq - 用户QQ号
   * @param {string} game - 游戏标识 ('gs', 'sr', 或 undefined 表示所有)
   * @returns {boolean|object} 
   */
  getUserAutoSign(qq, game) {
    const user = this.getUser(qq)
    if (!user) return game ? false : { gs: false, sr: false }
    
    const autoSign = user.autoSign || {}
    
    if (game) {
      return autoSign[game] === true
    }
    
    return {
      gs: autoSign.gs === true,
      sr: autoSign.sr === true
    }
  }

  /**
   * 设置用户自动签到
   * @param {string} qq - 用户QQ号
   * @param {string} game - 游戏标识 ('gs', 'sr', 或 'all')
   * @param {boolean} enabled - 是否开启
   */
  setUserAutoSign(qq, game, enabled) {
    const user = this.getUser(qq) || {}
    const autoSign = user.autoSign || {}
    
    if (game === 'all') {
      autoSign.gs = enabled
      autoSign.sr = enabled
    } else {
      autoSign[game] = enabled
    }
    
    return this.saveUser(qq, { autoSign })
  }

  /**
   * 获取所有开启自动签到的用户
   * @param {string} game - 游戏标识 ('gs', 'sr')
   * @returns {Array} 用户列表
   */
  getAutoSignUsers(game = 'gs') {
    const users = this.getUsers()
    const result = []
    
    for (const [qq, userData] of Object.entries(users)) {
      if (!userData.cookie) continue
      
      const autoSign = userData.autoSign || {}
      
      // 检查该游戏是否开启自动签到（必须明确为true）
      if (autoSign[game] === true) {
        result.push({
          qq,
          uid: userData.uid,
          cookie: userData.cookie,
          game
        })
      }
    }
    
    return result
  }

  /**
   * 获取签到日志
   */
  getSignLogs() {
    return this.readJSON(this.signLogFile)
  }

  /**
   * 保存签到日志
   */
  saveSignLogs(logs) {
    return this.writeJSON(this.signLogFile, logs)
  }

  /**
   * 添加签到日志（新版：支持分游戏记录）
   * @param {string} qq - 用户QQ号
   * @param {string} game - 游戏标识 ('gs', 'sr')
   * @param {string} uid - 游戏UID
   * @param {object} result - 签到结果
   */
  addSignLog(qq, game, uid, result) {
    const logs = this.getSignLogs()
    const today = new Date().toLocaleDateString('zh-CN')
    
    if (!logs[today]) {
      logs[today] = {}
    }
    
    if (!logs[today][qq]) {
      logs[today][qq] = {}
    }
    
    // 分游戏记录
    logs[today][qq][game] = {
      uid,
      result,
      time: Date.now()
    }

    // 只保留最近30天的日志
    const dates = Object.keys(logs).sort()
    if (dates.length > 30) {
      const oldDates = dates.slice(0, dates.length - 30)
      oldDates.forEach(date => delete logs[date])
    }

    return this.saveSignLogs(logs)
  }

  /**
   * 获取用户今日签到记录
   * @param {string} qq - 用户QQ号
   * @param {string} game - 游戏标识 ('gs', 'sr')，不传则返回全部
   * @returns {object|null}
   */
  getTodaySignLog(qq, game = null) {
    const logs = this.getSignLogs()
    const today = new Date().toLocaleDateString('zh-CN')
    const todayLog = logs[today]?.[qq]
    
    if (!todayLog) return null
    
    // 如果指定游戏，返回该游戏的记录
    if (game) {
      return todayLog[game] || null
    }
    
    // 否则返回全部
    return todayLog
  }

  /**
   * 获取用户签到统计
   * @param {string} qq - 用户QQ号
   * @param {string} game - 游戏标识 ('gs', 'sr')，不传则统计全部
   * @returns {object} { total, success, signedToday }
   */
  getUserSignStats(qq, game = null) {
    const logs = this.getSignLogs()
    const today = new Date().toLocaleDateString('zh-CN')
    let total = 0
    let success = 0
    let signedToday = false
    
    for (const [date, dayLogs] of Object.entries(logs)) {
      if (dayLogs[qq]) {
        const userLog = dayLogs[qq]
        
        // 如果指定游戏，只统计该游戏
        if (game) {
          if (userLog[game]) {
            total++
            if (userLog[game].result?.success) {
              success++
            }
            if (date === today) {
              signedToday = true
            }
          }
        } else {
          // 统计所有游戏（新版数据格式：{ gs: {...}, sr: {...} }）
          for (const gameLog of Object.values(userLog)) {
            if (gameLog && gameLog.uid && gameLog.result) {
              total++
              if (gameLog.result?.success) {
                success++
              }
              if (date === today) {
                signedToday = true
              }
            }
          }
        }
      }
    }
    
    return { total, success, signedToday }
  }

  /**
   * 获取用户推送配置
   * @param {string} qq - 用户QQ号
   * @returns {object} { groupId, privateSuccess, privateFail }
   */
  getUserPushConfig(qq) {
    const user = this.getUser(qq)
    return user?.pushConfig || {
      groupId: null,          // 推送的群聊ID
      privateSuccess: false,  // 私聊推送成功消息（默认关闭）
      privateFail: false      // 私聊推送失败消息（默认关闭）
    }
  }

  /**
   * 设置用户推送配置
   * @param {string} qq - 用户QQ号
   * @param {object} config - 推送配置
   */
  setUserPushConfig(qq, config) {
    const user = this.getUser(qq) || {}
    const currentConfig = user.pushConfig || {}
    
    return this.saveUser(qq, {
      pushConfig: {
        ...currentConfig,
        ...config
      }
    })
  }

  /**
   * 设置用户开启自动签到的群聊
   * @param {string} qq - 用户QQ号
   * @param {string} groupId - 群聊ID
   */
  setUserAutoSignGroup(qq, groupId) {
    return this.setUserPushConfig(qq, { groupId })
  }

  /**
   * 获取所有需要推送的用户（按群聊分组）
   * @returns {object} { groupId: [users], private: [users] }
   */
  getPushUsers() {
    const users = this.getUsers()
    const result = {
      groups: {},  // 群聊推送：{ groupId: [{ qq, pushConfig }] }
      private: []  // 私聊推送：[{ qq, pushConfig }]
    }
    
    for (const [qq, userData] of Object.entries(users)) {
      const pushConfig = userData.pushConfig
      if (!pushConfig) continue
      
      // 群聊推送
      if (pushConfig.groupId) {
        if (!result.groups[pushConfig.groupId]) {
          result.groups[pushConfig.groupId] = []
        }
        result.groups[pushConfig.groupId].push({ qq, pushConfig })
      }
      
      // 私聊推送
      if (pushConfig.privateSuccess || pushConfig.privateFail) {
        result.private.push({ qq, pushConfig })
      }
    }
    
    return result
  }
}

// 导出单例
export default new Storage()

